package com.qf.realm;

import com.qf.pojo.SysUsers;
import com.qf.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

/**
 * @author 汤奇
 * @version V1.0
 * @Project BookPro
 * @Package com.qf.realm
 * @Description: 自定义Realm类
 *                  1.获取数据库中的用户名密码:根据用户名,到mysql数据库的用户表中查询数据库中的用户名密码,
 *                      交给SecurityManager核心对象
 *                  2.授权:如果用户名密码正确,赋予用户对应的角色和权限
 * @Date 2022/6/15 0:16
 */
public class MyUserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    /**
     * 授权方法:用户名密码校验成功后自动执行这个方法进行用户授权,赋予用户对应的角色和权限
     * @param principalCollection shiro框架中在session会话里面存储的当前登录用户的对象
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("=======自定义Realm,doGetAuthorizationInfo方法,授权:根据用户名获取用户的角色权限数据赋予这个用户======");
        //1.获取认证的时候shiro框架中的session存储的用户对象
        SysUsers user = (SysUsers) principalCollection.getPrimaryPrincipal();
        int id = user.getId();

        //2.根据用户id,到数据库角色表中获取用户的角色信息
        Set<String> roles = userService.findRolesByUid(id);

        //3.根据用户id,到数据库权限表或者菜单表中获取用户的权限信息
        Set<String> perms = userService.findPermByUid(id);

        //4.封装shiro规定的角色权限对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //5.将角色数据赋予shiro的权限对象
        authorizationInfo.setRoles(roles);

        //6.将权限数据赋予shiro权限对象
        authorizationInfo.setStringPermissions(perms);

        //7.返回shiro的权限对象给,SecurityManager核心读写
        return authorizationInfo;
    }

    /**
     * 认证方法:重mysql中,根据用户名,获取user表中的用户对象,交给shiro框架的SecurityManager核心管理
     * @param token 消费者在页面输入的用户名,密码对象
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("=======自定义Realm,doGetAuthenticationInfo方法,登录认证:判断用户名密码是否正确======");
        //1.获取用户在登录页面中输入的用户名
        String userName = (String) token.getPrincipal();

        //2.获取用户在登录页输入的密码,shiro规定密码必须转换成char类型数组,在转换成String字符串
        String password = new String((char[]) token.getCredentials());

        //3.根据用户名到数据库用户表中获取用户对象
        SysUsers user = userService.findUserByName(userName);

        //4.如果用户对象获取不到,抛异常,用户不存在
        if (user == null) {
            throw new UnknownAccountException("用户不存在!");
        }

        //5.如果用户对象获取到,对比密码是否正确
        if (!password.equals(user.getPassword())){
            //6.如果密码不对抛异常,密码错误
            throw new IncorrectCredentialsException("密码错误!");
        }

        //7.如果密码正确,封装返回的用户对象给shiro框架的SecurityManager核心
        //第一参数:用户对象,第二参数:密码,第三参数:当前自定义realm对象的名称
        return new SimpleAuthenticationInfo(user, password, getName());
    }
}
